﻿Imports System.Windows
Imports System.Xml.Serialization
Imports System.IO
Imports System.Text
Imports System.Xml
Imports System.Linq
 
Imports <xmlns:g="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2">
Imports <xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2">
Imports <xmlns:gpx="http://www.topografix.com/GPX/1/1">

Public Class GarminHelper
    Public Class TrackPoint
        Private _time As DateTime

        Public Property Time() As DateTime
            Get
                Return _time
            End Get
            Set (ByVal value As DateTime)
                _time = value
            End Set
        End Property

        Private _position As Point

        Public Property Position() As Point
            Get
                Return _position
            End Get
            Set (ByVal value As Point)
                _position = value
            End Set
        End Property

        Private _heartRate As Integer

        Public Property HeartRate() As Integer
            Get
                Return _heartRate
            End Get
            Set (ByVal value As Integer)
                _heartRate = value
            End Set
        End Property

        Private _power As Integer

        Public Property Power() As Integer
            Get
                Return _power
            End Get
            Set (ByVal value As Integer)
                _power = value
            End Set
        End Property

        Private _speed As Integer

        Public Property Speed() As Integer
            Get
                Return _speed
            End Get
            Set (ByVal value As Integer)
                _speed = value
            End Set
        End Property

        Private _cadence As Integer

        Public Property Cadence() As Integer
            Get
                Return _cadence
            End Get
            Set (ByVal value As Integer)
                _cadence = value
            End Set
        End Property


        Private _distance As Double

        Public Property Distance() As Double
            Get
                Return _distance
            End Get
            Set (ByVal value As Double)
                _distance = value
            End Set
        End Property

        Private _image As Byte()

        Public Property Image() As Byte()
            Get
                Return _image
            End Get
            Set (ByVal value As Byte())
                _image = value
            End Set
        End Property

        Private _altitudeMeters As Double

        Public Property AltitudeMeters() As Double
            Get
                Return _altitudeMeters
            End Get
            Set (ByVal value As Double)
                _altitudeMeters = value
            End Set
        End Property
    End Class


    Public Shared Function LoadGPX (ByVal filename As String) As List(Of TrackPoint)


        Dim doc As XDocument = XDocument.Load (filename)

        Dim query = From tp In doc...<gpx:trkpt> _
                Select New TrackPoint With { _
                .Position = New Point() With { _
                .X = CType (tp.<gpx:Position>.<g:LatitudeDegrees>.Value, Double), _
                .Y = CType (tp.<g:Position>.<g:LongitudeDegrees>.Value, Double) _
                } _
                }

    End Function

    Public Shared Function Load (ByVal filename As String) As List(Of TrackPoint)
        Dim doc As XDocument = XDocument.Load (filename)

        Dim query = From tp In doc...<g:Trackpoint> _
                Select New TrackPoint With { _
                .Time = CType (tp.<g:Time>.Value, DateTime), _
                .HeartRate = CType (tp.<g:HeartRateBpm>.Value, Integer), _
                .Cadence = CType (tp.<g:Cadence>.Value, Integer), _
                .AltitudeMeters = CType (tp.<g:AltitudeMeters>.Value, Double), _
                .Power = CType (tp.<g:Extensions>.<ns3:TPX>.<ns3:Watts>.Value, String), _
                .Speed = CType (tp.<g:Extensions>.<ns3:TPX>.<ns3:Speed>.Value, String), _
                .Position = New Point() With { _
                .X = CType (tp.<g:Position>.<g:LatitudeDegrees>.Value, Double), _
                .Y = CType (tp.<g:Position>.<g:LongitudeDegrees>.Value, Double) _
                }, _
                .Distance = CType (tp.<g:DistanceMeters>.Value, Double) _
                }


        ' --- get ones which have moved


        Dim l As List(Of TrackPoint) = query.Where (Function(tp) tp.Position.X + tp.Position.Y <> 0) _
                .OrderBy (Function(tp) tp.Distance).ToList()

        Dim dataset As List(Of Integer()) = New List(Of Integer())()
        Dim tpAveraged As List(Of TrackPoint) = RollingAverage2 (l.ToList())

        Dim queryPower = From s In tpAveraged _
                Let s1 As Integer = CType(s.Power, _
             Integer) _
                Select s1

        Dim queryAlt = From s In tpAveraged _
                Let s1 As Integer = CType(s.AltitudeMeters, _
             Integer) _
                Select s1

        Dim querySpeed = From s In tpAveraged _
                Let s1 As Integer = CType(s.Speed, _
             Integer) _
                Select s1

        Dim queryHR = From s In tpAveraged _
                Let s1 As Integer = CType(s.HeartRate, _
             Integer) _
                Select s1


        Return l

        'dataset.Add()
        ' dataset.Add(queryHR.ToArray())
        dataset.Add (queryPower.ToArray())
        'dataset.Add(queryAlt.ToArray())

        ' // Dim chart As LineChart = New LineChart(600, 200)
        ' chart.SetDatasetColors()
        '  chart.SetData(dataset)
        '  Dim url As String = chart.GetUrl()


        '  RollingAverage(l)
        Dim TCUser As New TCUser()
        Dim w As New Workout


    End Function

    Private _workoutTrackpoints As List(Of TrackPoint)

    Public Property WorkoutTrackpoints() As List(Of TrackPoint)
        Get
            Return _workoutTrackpoints
        End Get
        Set (ByVal value As List(Of TrackPoint))
            _workoutTrackpoints = value
        End Set
    End Property

    Private _rollingAverage As List(Of TrackPoint)

    Public Property RollingAverage() As List(Of TrackPoint)
        Get
            Return _rollingAverage
        End Get
        Set (ByVal value As List(Of TrackPoint))
            _rollingAverage = value
        End Set
    End Property

    Private _rollingAveragePower As List(Of Integer)

    Public Property RollingAveragePower() As List(Of Integer)
        Get
            Return _rollingAveragePower
        End Get
        Set (ByVal value As List(Of Integer))
            _rollingAveragePower = value
        End Set
    End Property

    Private _tss As Decimal

    Public Property TSS() As Decimal
        Get
            Return _tss
        End Get
        Set (ByVal value As Decimal)
            _tss = value
        End Set
    End Property

    Private _if As Decimal

    Public Property [IF]() As Decimal
        Get
            Return _if
        End Get
        Set (ByVal value As Decimal)
            _if = value
        End Set
    End Property

    Private _averagePower As Decimal

    Public Property AveragePower() As Decimal
        Get
            Return _averagePower
        End Get
        Set (ByVal value As Decimal)
            _averagePower = value
        End Set
    End Property

    Private _averageSpeed As Decimal

    Public Property AverageSpeed() As Decimal
        Get
            Return _averageSpeed
        End Get
        Set (ByVal value As Decimal)
            _averageSpeed = value
        End Set
    End Property

    Public Shared Function RollingAverage2 (ByVal list As List(Of TrackPoint)) As List(Of TrackPoint)

        Dim tLast As DateTime = list (0).Time
        Dim tCurrent As DateTime = list (0).Time
        Dim n As Integer = 0
        Dim cCurrent As Decimal

        Dim chunk As New List(Of TrackPoint)
        Dim finalAveraged As New List(Of Decimal)

        Dim averagedTrackpoins As New List(Of TrackPoint)


        Dim elapsed_time As TimeSpan

        For Each tp As TrackPoint In list

            elapsed_time = tCurrent.Subtract (tLast)
            If (elapsed_time.Seconds) >= 30 Then
                ' --- 30 seconds
                tLast = tCurrent

                Dim averageOrderCount = Aggregate cust In chunk _
                        Into Average(cust.Power)


                Dim averageSpeed = Aggregate cust In chunk _
                        Into Average(cust.Speed)

                Dim averageHR = Aggregate cust In chunk _
                        Into Average(cust.HeartRate)

                Dim averageCadence = Aggregate cust In chunk _
                        Into Average(cust.Cadence)

                Dim averageAltitudeMeters = Aggregate cust In chunk _
                        Into Average(cust.AltitudeMeters)


                Dim newTP = New TrackPoint()
                newTP.Power = averageOrderCount
                newTP.Speed = averageSpeed
                newTP.HeartRate = averageHR
                newTP.Cadence = averageCadence
                newTP.AltitudeMeters = averageAltitudeMeters

                averagedTrackpoins.Add (newTP)

                'reset
                chunk = New List(Of TrackPoint)
                Dim d As Decimal

                d = averageOrderCount^4
                finalAveraged.Add (d)


            End If

            chunk.Add (tp)

            n = n + 1
            tCurrent = tp.Time

            'tCurrent = list(n).Time
        Next

        Return averagedTrackpoins
    End Function


    Public Function CalcRollingAverage (ByVal list As List(Of TrackPoint), ByVal interval As Integer) _
        As List(Of TrackPoint)

        Dim tLast As DateTime = list (0).Time
        Dim tCurrent As DateTime = list (0).Time
        Dim n As Integer = 0
        Dim cCurrent As Decimal

        Dim chunk As New List(Of TrackPoint)

        Dim finalAveraged As New List(Of Double)

        Dim finalTrackpoints As New List(Of TrackPoint)


        Dim elapsed_time As TimeSpan

        For Each tp As TrackPoint In list

            elapsed_time = tCurrent.Subtract (tLast)
            If (elapsed_time.Seconds) >= 30 Then
                ' --- 30 seconds
                tLast = tCurrent

                Dim averageOrderCount = Aggregate cust In chunk _
                        Into Average(cust.Power)

                chunk = New List(Of TrackPoint)
                Dim d As Decimal

                d = averageOrderCount^4
                finalAveraged.Add (d)

                Dim trackpointChunk As New TrackPoint()
                trackpointChunk.Power = d
                trackpointChunk.Time = tCurrent
                finalTrackpoints.Add (trackpointChunk)
            End If

            chunk.Add (tp)

            n = n + 1
            tCurrent = tp.Time

            'tCurrent = list(n).Time
        Next

        Return finalTrackpoints

    End Function


    Public Function caclCTL()
        ' calcs for act ctl
        Dim TSB As Integer
        Dim TSSCurrent As Decimal

        Dim CTL As Decimal
        Dim atl As Decimal

        Dim StartingCTL As Decimal = 0
        Dim StartingATL As Decimal = 0

        Dim CTLConst As Decimal = 42
        Dim ATLConst As Decimal = 7

        Dim prevCTL As Decimal = 4
        Dim prevATL As Decimal = 4


        Dim CTLList As New List(Of Double)
        Dim ATLList As New List(Of Double)

        Dim r As New Random()
        For index As Integer = 1 To 100
            ' =RC[-2]*(1-EXP(-1/ctl_const))+R[-1]C*EXP(-1/ctl_const)
            CTL = TSS*(1 - Math.Exp (- 1/CTLConst)) + prevCTL*(Math.Exp (- 1/CTLConst))
            atl = TSS*(1 - Math.Exp (- 1/ATLConst)) + prevATL*(Math.Exp (- 1/ATLConst))

            prevATL = atl
            prevCTL = CTL

            CTLList.Add (CTL)
            ATLList.Add (atl)

            TSS = r.Next (0, 130)
        Next

        ATLList.ToArray()
    End Function

    'Public Shared Function RollingAverage(ByVal list As List(Of TrackPoint)) As List(Of Decimal)

    '    Dim tLast As DateTime = list(0).Time
    '    Dim tCurrent As DateTime = list(0).Time
    '    Dim n As Integer = 0
    '    Dim cCurrent As Decimal

    '    Dim chunk As New List(Of TrackPoint)

    '    Dim finalAveraged As New List(Of Double)

    '    Dim elapsed_time As TimeSpan

    '    For Each tp As TrackPoint In list

    '        elapsed_time = tCurrent.Subtract(tLast)
    '        If (elapsed_time.Seconds) >= 30 Then
    '            ' --- 30 seconds
    '            tLast = tCurrent

    '            Dim averageOrderCount = Aggregate cust In chunk _
    '            Into Average(cust.Power)

    '            chunk = New List(Of TrackPoint)
    '            Dim d As Decimal

    '            d = averageOrderCount ^ 4
    '            finalAveraged.Add(d)


    '        End If

    '        chunk.Add(tp)

    '        n = n + 1
    '        tCurrent = tp.Time

    '        'tCurrent = list(n).Time
    '    Next

    '    Dim average4thPower = Aggregate power In finalAveraged _
    '           Into Average(power)

    '    Dim averagePowerUncorrected = Aggregate allTrackpoints In list _
    '        Into Average(allTrackpoints.Power)

    '    ' --- Get the total duration
    '    tLast = list(0).Time
    '    elapsed_time = tCurrent.Subtract(tLast)
    '    Dim duration As Decimal = elapsed_time.TotalHours

    '    Dim LTpower As Decimal = 300

    '    Dim dec2 As Decimal = average4thPower ^ (1 / 4)
    '    Dim ifactor = dec2 / LTpower

    '    Dim TSS As Decimal = duration * (averagePowerUncorrected / LTpower) ^ 2

    '    ' calcs for act ctl
    '    Dim TSB As Integer
    '    Dim TSSCurrent As Decimal

    '    Dim CTL As Decimal
    '    Dim atl As Decimal

    '    Dim StartingCTL As Decimal = 0
    '    Dim StartingATL As Decimal = 0

    '    Dim CTLConst As Decimal = 42
    '    Dim ATLConst As Decimal = 7

    '    Dim prevCTL As Decimal = 4
    '    Dim prevATL As Decimal = 4


    '    Dim CTLList As New List(Of Double)
    '    Dim ATLList As New List(Of Double)

    '    Dim r As New Random()
    '    For index As Integer = 1 To 100
    '        ' =RC[-2]*(1-EXP(-1/ctl_const))+R[-1]C*EXP(-1/ctl_const)
    '        CTL = TSS * (1 - Exp(-1 / CTLConst)) + prevCTL * (Exp(-1 / CTLConst))
    '        atl = TSS * (1 - Exp(-1 / ATLConst)) + prevATL * (Exp(-1 / ATLConst))

    '        prevATL = atl
    '        prevCTL = CTL

    '        CTLList.Add(CTL)
    '        ATLList.Add(atl)

    '        TSS = r.Next(0, 130)
    '    Next

    '    ATLList.ToArray()


    'End Function


    Public Function ReadGarminDatabaseXML (ByVal xml As String) As TrainingCenterDatabase_t
        ' Create an instance of the XmlSerializer class;
        ' specify the type of object to be deserialized.
        Dim serializer As New XmlSerializer (GetType (TrainingCenterDatabase_t))
        ' If the XML document has been altered with unknown
        ' nodes or attributes, handle them with the
        ' UnknownNode and UnknownAttribute events.
        AddHandler serializer.UnknownNode, AddressOf serializer_UnknownNode
        AddHandler serializer.UnknownAttribute, AddressOf serializer_UnknownAttribute

        ' A FileStream is needed to read the XML document.
        Dim ms As New MemoryStream

        Dim sr As StreamReader = New StreamReader (xml)
        Dim enc As New UTF8Encoding
        Dim arrBytData() As Byte = enc.GetBytes (xml)
        ms.Write (arrBytData, 0, arrBytData.Length)

        'The stream contains the data in mamory, in binary form.
        'You can utilize the stream for further operations here

        ' Declare an object variable of the type to be deserialized.
        Dim pe As TrainingCenterDatabase_t
        ' Use the Deserialize method to restore the object's state with
        ' data from the XML document. 
        pe = CType (serializer.Deserialize (sr), TrainingCenterDatabase_t)
        ' Read the order date.
        ' Console.WriteLine(("Length: " & pe.Workouts.Length))

        ms.Close()


        ms = Nothing
        Return pe

    End Function

    Private Sub serializer_UnknownNode (ByVal sender As Object, ByVal e As XmlNodeEventArgs)
        Console.WriteLine (("Unknown Node:" & e.Name & ControlChars.Tab & e.Text))
    End Sub

    'serializer_UnknownNode


    Private Sub serializer_UnknownAttribute (ByVal sender As Object, ByVal e As XmlAttributeEventArgs)
        Dim attr As XmlAttribute = e.Attr
        Console.WriteLine (("Unknown attribute " & attr.Name & "='" & attr.Value & "'"))
    End Sub

    'serializer_UnknownAttribute
End Class
